//
// Created by root on 6/18/17.
//

#include <stdlib.h>
#include "runner_fa.h"

int setup_fa(void **state) {
    return 0;
}

int teardown_fa(void **state) {
    return 0;
}

// statement //

// {define function {add}: {add {a} {b}} as {{a} + {b}}}
Statement *create_statement_1() {
    Statement *s = (Statement *)malloc(sizeof(Statement));
    Statement *arg1 = NULL;
    Statement *arg2 = NULL;
    Statement *arg3 = NULL;
    Statement *arg4 = NULL;
    Statement *arg5 = NULL;
    Statement *arg6 = NULL;
    Statement *arg7 = NULL;
    s->symbol = NULL;
    s->type = ARG;
    s->children = init_queue();
    add_statement(s, "define", SYM);
    add_statement(s, "function", SYM);
    arg1 = add_statement(s, NULL, ARG);
    add_statement(arg1, "add", SYM);
    add_statement(s, ":", SYM);
    arg2 = add_statement(s, NULL, ARG);
    add_statement(arg2, "add", SYM);
    arg3 = add_statement(arg2, NULL, ARG);
    add_statement(arg3, "a", SYM);
    arg4 = add_statement(arg2, NULL, ARG);
    add_statement(arg4, "b", SYM);
    add_statement(s, "as", SYM);
    arg5 = add_statement(s, NULL, ARG);
    arg6 = add_statement(arg5, NULL, ARG);
    add_statement(arg6, "a", SYM);
    add_statement(arg5, "+", SYM);
    arg7 = add_statement(arg5, NULL, ARG);
    add_statement(arg7, "b", SYM);
    return s;
}

// {case {when {a} then {b} ...} else {c}}
Statement *create_loop_statement_1() {
    Statement *s = (Statement *)malloc(sizeof(Statement));
    Statement *arg1 = NULL;
    Statement *arg2 = NULL;
    Statement *arg3 = NULL;
    Statement *arg4 = NULL;
    s->symbol = NULL;
    s->type = ARG;
    s->children = init_queue();
    add_statement(s, "case", SYM);
    arg1 = add_statement(s, NULL, LOOP);
    add_statement(arg1, "when", SYM);
    arg2 = add_statement(arg1, NULL, ARG);
    add_statement(arg2, "a", SYM);
    add_statement(arg1, "then", SYM);
    arg3 = add_statement(arg1, NULL, ARG);
    add_statement(arg3, "b", SYM);
    // add_statement(arg1, ",", SYM);  //comma is ignored
    add_statement(arg1, "...", SYM);
    add_statement(s, "else", SYM);
    arg4 = add_statement(s, NULL, ARG);
    add_statement(arg4, "c", SYM);
    return s;
}

// {let {{var} = {value} ...} in {{expr} ...}}
Statement *create_loop_statement_2() {
    Statement *s = (Statement *)malloc(sizeof(Statement));
    Statement *arg1 = NULL;
    Statement *arg2 = NULL;
    Statement *arg3 = NULL;
    Statement *arg4 = NULL;
    Statement *arg5 = NULL;
    s->symbol = NULL;
    s->type = ARG;
    s->children = init_queue();
    add_statement(s, "let", SYM);
    arg1 = add_statement(s, NULL, LOOP);
    arg2 = add_statement(arg1, NULL, ARG);
    add_statement(arg2, "var", SYM);
    add_statement(arg1, "=", SYM);
    arg3 = add_statement(arg1, NULL, ARG);
    add_statement(arg3, "value", SYM);
    // add_statement(arg1, ",", SYM);
    add_statement(arg1, "...", SYM);
    add_statement(s, "in", SYM);
    arg4 = add_statement(s, NULL, LOOP);
    arg5 = add_statement(arg4, NULL, ARG);
    add_statement(arg5, "expr", SYM);
    add_statement(arg4, "...", SYM);
    return s;
}

// {if {if_clause} then {then_clause} {else {else_clause} ..}}
Statement *create_optional_statement_1() {
    Statement *s = (Statement *)malloc(sizeof(Statement));
    Statement *arg1 = NULL;
    Statement *arg2 = NULL;
    Statement *arg3 = NULL;
    Statement *arg4 = NULL;
    s->symbol = NULL;
    s->type = ARG;
    s->children = init_queue();
    add_statement(s, "if", SYM);
    arg1 = add_statement(s, NULL, ARG);
    add_statement(arg1, "if_clause", SYM);
    add_statement(s, "then", SYM);
    arg2 = add_statement(s, NULL, ARG);
    add_statement(arg2, "then_clause", SYM);
    arg3 = add_statement(s, NULL, OPTIONAL);
    // add_statement(arg3, ",", SYM);  //comma is ignored
    add_statement(arg3, "else", SYM);
    arg4 = add_statement(arg3, NULL, ARG);
    add_statement(arg4, "else_clause", SYM);
    add_statement(arg3, "..", SYM);
    return s;
}

// mapping //

// {{x} + {y}}
static Statement *create_source_statement_1() {
    Statement *s = (Statement *)malloc(sizeof(Statement));
    Statement *arg1 = NULL;
    Statement *arg2 = NULL;
    s->symbol = NULL;
    s->type = ARG;
    s->children = init_queue();
    arg1 = add_statement(s, NULL, ARG);
    add_statement(arg1, "x", SYM);
    add_statement(s, "+", SYM);
    arg2 = add_statement(s, NULL, ARG);
    add_statement(arg2, "y", SYM);
    return s;
}

// {(+ {x} {y})}
static Statement *create_target_statement_1() {
    Statement *s = (Statement *)malloc(sizeof(Statement));
    Statement *arg1 = NULL;
    Statement *arg2 = NULL;
    s->symbol = NULL;
    s->type = ARG;
    s->children = init_queue();
    add_statement(s, "(+", SYM);
    arg1 = add_statement(s, NULL, ARG);
    add_statement(arg1, "x", SYM);
    arg2 = add_statement(s, NULL, ARG);
    add_statement(arg2, "y", SYM);
    add_statement(s, ")", SYM);
    return s;
}

// {{x} + {y}} -> {(+ {x} {y})}
Mapping *create_mapping_1() {
    Mapping *m = (Mapping *) malloc(sizeof(Mapping));
    m->sys = NULL;
    m->isMacro = FALSE;
    m->className = "";
    m->functionName = "";
    m->source = copy_string("{{x} + {y}}");
    m->target = copy_string("{(+ {x} {y})}");
    m->sourceStatement = create_source_statement_1();
    m->targetStatement = create_target_statement_1();
    m->starter = to_dfa(m->sourceStatement);
    return m;
}

// {{x} or {y}}
static Statement *create_source_statement_2() {
    Statement *s = (Statement *)malloc(sizeof(Statement));
    Statement *arg1 = NULL;
    Statement *arg2 = NULL;
    s->symbol = NULL;
    s->type = ARG;
    s->children = init_queue();
    arg1 = add_statement(s, NULL, ARG);
    add_statement(arg1, "x", SYM);
    add_statement(s, "or", SYM);
    arg2 = add_statement(s, NULL, ARG);
    add_statement(arg2, "y", SYM);
    return s;
}

// {(or {x} {y})}
static Statement *create_target_statement_2() {
    Statement *s = (Statement *)malloc(sizeof(Statement));
    Statement *arg1 = NULL;
    Statement *arg2 = NULL;
    s->symbol = NULL;
    s->type = ARG;
    s->children = init_queue();
    add_statement(s, "(or", SYM);
    arg1 = add_statement(s, NULL, ARG);
    add_statement(arg1, "x", SYM);
    arg2 = add_statement(s, NULL, ARG);
    add_statement(arg2, "y", SYM);
    add_statement(s, ")", SYM);
    return s;
}

// {{x} or {y}} -> {(or {x} {y})}
Mapping *create_mapping_2() {
    Mapping *m = (Mapping *) malloc(sizeof(Mapping));
    m->sys = NULL;
    m->isMacro = FALSE;
    m->className = "";
    m->functionName = "";
    m->source = copy_string("{{x} or {y}}");
    m->target = copy_string("{(or {x} {y})}");
    m->sourceStatement = create_source_statement_2();
    m->targetStatement = create_target_statement_2();
    m->starter = to_dfa(m->sourceStatement);
    return m;
}

// {case {when {a} then {b} , ...} else {c}}
static Statement *create_source_statement_3() {
    return create_loop_statement_1();
}

// {(cond {({a} {b}) ...} (else {c}))}
static Statement *create_target_statement_3() {
    Statement *s = (Statement *)malloc(sizeof(Statement));
    Statement *arg1 = NULL;
    Statement *arg2 = NULL;
    Statement *arg3 = NULL;
    Statement *arg4 = NULL;
    s->symbol = NULL;
    s->type = ARG;
    s->children = init_queue();
    add_statement(s, "(cond", SYM);
    arg1 = add_statement(s, NULL, LOOP);
    add_statement(arg1, "(", SYM);
    arg2 = add_statement(arg1, NULL, ARG);
    add_statement(arg2, "a", SYM);
    arg3 = add_statement(arg1, NULL, ARG);
    add_statement(arg3, "b", SYM);
    add_statement(arg1, ")", SYM);
    add_statement(arg1, "...", SYM);
    add_statement(s, "(else", SYM);
    arg4 = add_statement(s, NULL, ARG);
    add_statement(arg4, "c", SYM);
    add_statement(s, "))", SYM);
    return s;
}

// {case {when {a} then {b} , ...} else {c}} -> {(cond {({a} {b}) ...} (else {c}))}
Mapping *create_mapping_3() {
    Mapping *m = (Mapping *) malloc(sizeof(Mapping));
    m->sys = NULL;
    m->isMacro = FALSE;
    m->className = "";
    m->functionName = "";
    m->source = copy_string("{case {when {a} then {b} , ...} else {c}}");
    m->target = copy_string("{(cond {({a} {b}) ...} (else {c}))}");
    m->sourceStatement = create_source_statement_3();
    m->targetStatement = create_target_statement_3();
    m->starter = to_dfa(m->sourceStatement);
    return m;
}

// {define template {name}: {template} as {statement}}
static Statement *create_sys_statement_1() {
    Statement *s = (Statement *)malloc(sizeof(Statement));
    Statement *arg1 = NULL;
    Statement *arg2 = NULL;
    Statement *arg3 = NULL;
    s->symbol = NULL;
    s->type = ARG;
    s->children = init_queue();
    add_statement(s, "define", SYM);
    add_statement(s, "template", SYM);
    arg1 = add_statement(s, NULL, ARG);
    add_statement(arg1, "name", SYM);
    add_statement(s, ":", SYM);
    arg2 = add_statement(s, NULL, ARG);
    add_statement(arg2, "template", SYM);
    add_statement(s, "as", SYM);
    arg3 = add_statement(s, NULL, ARG);
    add_statement(arg3, "statement", SYM);
    return s;
}

static SysBlock *create_sys_block_1() {
    SysBlock *sys = (SysBlock *) malloc(sizeof(SysBlock));
    sys->name = copy_string(SYS_TEMPLATE_NAME);
    sys->function = "";
    sys->mapping = "";
    sys->run = copy_string(SYS_TEMPLATE_PREPARE);
    sys->eval = copy_string(SYS_TEMPLATE_EVAL);
    return sys;
}

Mapping *create_sys_mapping_1() {
    Mapping *m = (Mapping *) malloc(sizeof(Mapping));
    m->sys = create_sys_block_1();
    m->isMacro = FALSE;
    m->className = "";
    m->functionName = "";
    m->source = copy_string(SYS_TEMPLATE_STATEMENT);
    m->target = NULL;
    m->sourceStatement = create_sys_statement_1();
    m->targetStatement = NULL;
    m->starter = to_dfa(m->sourceStatement);
    return m;
}

